home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 011 / cache.arc / CACHE.ASM next >
Encoding:
Assembly Source File  |  1986-01-24  |  25.4 KB  |  555 lines

  1. INTERRUPTS      SEGMENT AT 0H    ;This is where the disk interrupt
  2.         ORG     13H*4            ;holds the address of its service routine
  3. DISK_INT        LABEL   DWORD  
  4. INTERRUPTS      ENDS
  5.  
  6. CODE_SEG        SEGMENT
  7.                 ASSUME  CS:CODE_SEG
  8.                 org     2h
  9. pspsize         dw                      ;size of physical machine
  10.                 org     80h
  11. parml           db      0  
  12.                 org     81h
  13. parm            db      127 dup (' ')
  14.  
  15.                 ORG     100H            ;ORG = 100H  this is a .COM file
  16. FIRST:          JMP     load_pgm        ;jump to initialize routine
  17.                                 
  18. CPY_RGT DB      '(C)85S.Holzner'        ;A signature in bytes
  19.  
  20. TBL_LEN         DW      40h     ;<-- # OF SECTORS IN CACHE, MIN=24, MAX=124.
  21.   
  22. entries         dw      0       ;used to count calls
  23. matches         dw      0       ;count hits
  24. highwater       dw      0       ;number of sectors in cache used
  25. TIME            DW      0       ;Time used to time-stamp each sector
  26. OLD_CX          DW      0       ;Stores original value of CX (CX is used often)
  27. LOW_TIM         DW      0       ;Used in searching for least recently used sect.
  28. INT13H          DD      0       ;Stores the original INT 13H address
  29. RET_ADR         LABEL   DWORD   ;Playing games with the stack here to preserve 
  30. RET_ADR_WORD    DW      2 DUP(0)            ;flags returned by Int 13H
  31. drive           db      0ffh     ;specific crive to be cached, if any 1,2,3,4...
  32.  
  33. DISK_CACHE      PROC    FAR     ;The Disk interrupt will now come here.
  34.         ASSUME  CS:CODE_SEG     
  35.  
  36.         cmp     drive,0ffh      ;specific disk to be cached?
  37.         je      diskany         ;if not, just go on
  38.         cmp     dl,drive        ;if so, is this the right one?
  39.         jne     old_int         ;if not, just return
  40. diskany:
  41.         inc     entries         ;count entries into program
  42.  
  43.         CMP     AX,0201H        ;Is this a read (AH=2) of 1 sector (AL=1)?
  44.         JE      READ            ;Yes, jump to Read
  45.         CMP     AH,3            ;No. Perchance a write or format?
  46.         JB      OLD_INT         ;No, release control to old disk Int.
  47.         JMP     WRITE           ;Yes, jump to Write
  48.  
  49. OLD_INT:PUSHF                   ;Pushf for Int 13H's final Iret
  50.         CALL    INT13H          ;Call the Disk Int
  51.         JMP     PAST            ;And jump past all usual Pops
  52.  
  53. READ:   PUSH    BX              ;Push just about every register ever heard of
  54.         PUSH    CX
  55.         PUSH    DX
  56.         PUSH    DI      
  57.         PUSH    SI
  58.         PUSH    DS
  59.         PUSH    ES
  60.         MOV     DI,BX       ;Int 13H gets data address as ES:BX, switch to ES:DI
  61.         ASSUME  DS:CODE_SEG     ;Make sure all labels found correctly
  62.         PUSH    CS              ;Move CS into DS by pushing CS, popping DS
  63.         POP     DS
  64.         MOV     OLD_CX,CX       ;Save original CX since we're about to use it
  65.         CMP     DH,0            ;DH holds requested head -- head 0?        
  66.         JNE     NOT_FAT1        ;Nope, this can't be the first Fat sector  
  67.         CMP     CX,6            ;If this is the directory, check if we have a
  68.         JE      FAT1            ; new disk.
  69.         CMP     CX,2            ;Track 0 (CH)? Sector 2 (CL)?
  70.         JNE     NOT_FAT1        ;If not, this sure isn't the FAT1        
  71. FAT1:   CALL    Find_sector     ;DOS reads in this sector first to 
  72.                                 ;    check disk format
  73.         JCXZ    NONE            ;We'll use it for a check-sum. Do we have it
  74.         MOV     BX,DI           ; stored yet? CX=0-->no. If yes, restore BX
  75.         MOV     CX,OLD_CX       ; and CX from original values
  76.         PUSHF                   ;And now do the Pushf and call of Int13H to read
  77.         CALL    INT13H          ; FAT1
  78.         JC      ERR             ;If error, leave
  79.  
  80.         MOV     CX,256          ;No error, FAT1 was read, check our value
  81.         REPE    CMPSW           ; with CMPSW -- if no match, disk was changed
  82.         JCXZ    BYE             ;Everything checks out, Bingo, exit.
  83.  
  84.         LEA     SI,TABLE        ;New Disk! Zero all the old disk's sectors
  85.         MOV     CX,TBL_LEN      ;Loop over all entries, DL holds drive #
  86. CLR:    CMP     DS:[SI+2],DL    ;Is this stored sector from the old disk?
  87.         JNE     NO_CLR          ;Nope, don't clear this entry
  88.         MOV     WORD PTR DS:[SI],0      ;Match, zero this entry, zero first word
  89. NO_CLR: ADD     SI,518      ;Move on to next stored sector (512 bytes of stored 
  90.         LOOP    CLR         ; sector and 3 words of identification & time-stamp)
  91.         JMP     BYE             ;Reset for new disk, let's leave
  92.  
  93. NONE:   CALL    STORE_SECTOR    ;Store FAT1 if there was no match to it
  94.         JC      ERR             ;Error -- exit ungraciously
  95.         JMP     BYE             ;No Error, Bye.
  96.  
  97. NOT_FAT1:                       ;The requested sector was not FAT1. Let's
  98.         CALL    Find_sector     ;get it. Or do we have it already?
  99.         JCXZ    NO_MATCH        ;No, jump to No_Match, store sector
  100.         inc     matches
  101.         MOV     CX,512          ;ES:DI and DS:SI already set up from Find_sector
  102. REP     MOVSB                   ;Move 512 bytes to requested memory area
  103.  
  104.         CMP     WORD PTR [BX+4],0FFFFH          ;Is this a a directory sector?
  105.         JE      BYE             ;Yes, don't reset time (already highest poss.)
  106.         INC     TIME            ;No, reset the time, this sector just accessed
  107.         MOV     AX,TIME         ;Move time into Time word of sector's 3 words
  108.         MOV     [BX+4],AX       ; of identification
  109.         JMP     BYE             ;And leave. If there's an article you'd like to
  110.  
  111. NO_MATCH:                       ;see, by all means write in C/O PC Magazine.
  112.         CALL    STORE_SECTOR    ;Don't have this sector yet, get it.
  113.         JC      ERR             ;If read failed, exit with error
  114. BYE:    CLC                     ;The exit point. Clear carry flag, set AX=1
  115.         MOV     AX,1            ; CY=0 --> no error, AH=0 --> error code = 0
  116. ERR:    POP     ES              ;If error, preserve flags and AX with error code
  117.         POP     DS              ;Pop all conceivable registers (except AX)
  118.         POP     SI
  119.         POP     DI
  120.         POP     DX
  121.         POP     CX              ;Now that the flags are set, we want to get the
  122.         POP     BX              ;old flags off the stack (put there by original
  123.  
  124. PAST:   POP     CS:RET_ADR_WORD ;Int call) To do that we save the return address
  125.         POP     CS:RET_ADR_WORD[2]      ;first and then pop the flags harmlessly
  126.         POP     CS:OLD_CX       ;into Old_CX, and then jump to RET_ADR.
  127.         JMP     CS:RET_ADR      ;Done with read. Now let's consider write.
  128.  
  129. WRITE:  PUSH    BX              ;Push all registers, past and present
  130.         PUSH    CX              
  131.         PUSH    DX
  132.         PUSH    DI
  133.         PUSH    SI
  134.         PUSH    DS
  135.         PUSH    ES
  136.         PUSH    AX
  137.         CMP     AX,0301H        ;Is this a write of one sector?
  138.         JNE     NOSAVE          ;No, don't save it in the sector bank
  139.         PUSH    CS              ;Yep, set DS (for call to Int13H label) and
  140.         POP     DS              ; write this sector out
  141.         PUSHF     
  142.         CALL    INT13H
  143.         JNC     SAVE            ;If there was an error  don't save sector
  144.         POP     CS:OLD_CX       ;Save AH error code, Pop old AX into Old_CX
  145.         JMP     ERR             ;And jump to an ignoble exit
  146.  
  147. SAVE:   MOV     OLD_CX,CX       ;We're going to save this sector.
  148.         MOV     DI,BX           ;Set up DI for string move (to store written
  149.         CALL    Find_sector     ; sector. Do we have it in memory? (set SI)
  150.         JCXZ    LEAVE           ;Nope, Leave (like above's Bye).
  151.         XCHG    DI,SI           ;Exchange destination and source
  152.         PUSH    ES              ;Set up DS:SI to point to where data written
  153.         POP     DS              ; from. We'll then use a string move
  154.         PUSH    CS              ;Set up ES so ES:DI points to sector bank
  155.         POP     ES              ; SI was set by Find_sector, Xchg'd into DI
  156.         MOV     CX,512          ;Get ready to move 512 bytes
  157.         REP     MOVSB           ;Here we go
  158.  
  159. LEAVE:  POP     AX              ;Here we leave
  160.         JMP     BYE             ;Which only pops AX and then jumps to Bye
  161.  
  162. NOSAVE: PUSH    CS              ;More than 1 sector written, don't save but
  163.         POP     DS              ; do zero stored sectors that will be written
  164.         MOV     AH,0            ;Use AX as loop index (AL=# of sectors to write)
  165. TOP:    PUSH    CX              ;Save CX since destroyed by Find_sector
  166.         CALL    Find_sector      ;Do we have this one?
  167.         JCXZ    NOPE            ;Nope if CX = 0
  168.         MOV     WORD PTR [BX],0 ;There is a match, zero this sector
  169. NOPE:   POP     CX              ;Restore CX, the sector index
  170.         INC     CL              ;Move on to next one
  171.         DEC     AX              ;Decrement loop index
  172.         JNZ     TOP             ;And, unless that gives 0, go back again
  173. POPS:   POP     AX              ;Pop 'em all, starting with AX
  174.         POP     ES
  175.         POP     DS
  176.         POP     SI
  177.         POP     DI
  178.         POP     DX
  179.         POP     CX
  180.         POP     BX
  181.         JMP     OLD_INT         ;And go back to OLD_INT for write.
  182.  
  183. DISK_CACHE      ENDP
  184.  
  185. Find_sector     PROC    NEAR    ;This routine finds a sector in the sector bank
  186.         PUSH    AX              ;And returns SI set to sector's entry, BX set
  187.                                 ;to the beginning of the 'table' entry.
  188.                                 ;If there was no match, CX = 0       
  189.  
  190.  
  191.         LEA     SI,SECTOR_data      
  192.         LEA     BX,TABLE        
  193.  
  194.         MOV     AX,TBL_LEN      ; When Int13H called, CH=trk #, CL=sec. #
  195.         XCHG    AX,CX           ; DH=head #, DL=Drive #. Get Tbl_Len into CX
  196.  
  197. FIND:   CMP     DS:[BX],AX      ;Compare stored sector's original AX to current 
  198.         JNE     NO              ;If not, not.
  199.         CMP     DS:[BX+2],DX    ;If so, check DX of stored sector with current
  200.         JE      GOT_IT          ;Yes, there is a match, leave
  201. NO:     ADD     BX,518          ;Point to next Table entry
  202.         ADD     SI,518          ;And next sector too
  203.         LOOP    FIND            ;Keep looping until there is a match
  204.  
  205. GOT_IT: POP     AX              ;If there is no match, CX will be left 0
  206.         RET                     ;Return
  207.  
  208. Find_sector      ENDP
  209.  
  210. STORE_SECTOR    PROC    NEAR    ;This routine, as it says, stores sectors
  211.         MOV     BX,DI           ;Original BX (ES:BX was original data address)
  212.         MOV     CX,OLD_CX       ; and CX restored (CX=trk#, Sector#)
  213.         PUSHF                   ;Pushf for Int 13H's Iret and call it
  214.         CALL    INT13H
  215.         JNC     ALL_OK          ;If there was an exit, exit ignominiously
  216.         JMP     FIN             ;If error, leave CY flag set, code in AH, exit
  217.  
  218. ALL_OK: PUSH    CX              ;No error, push used registers
  219.         PUSH    BX              ; and find space for sector in sector bank
  220.         PUSH    DX
  221.         lea     DI,SECTOR_data      ;Point to sector bank
  222.         LEA     BX,TABLE        ; and Table
  223.  
  224.         MOV     CX,TBL_LEN      ; and get ready to loop over all of them to
  225. CHK0:   CMP     WORD PTR DS:[BX],0      ;find if there is an unused sector
  226.         JE      FOUND           ;If the first word is 0, use this sector
  227.         ADD     DI,518          ;But this one isn't so update DI, SI and 
  228.         ADD     BX,518          ; loop again
  229.         LOOP    CHK0  
  230.  
  231.         MOV     LOW_TIM,0FFFEH  ;All sectors were filled, find least recently
  232.         LEA     DI,SECTOR_data      ; used and write over that one
  233.         LEA     SI,TABLE
  234.         MOV     CX,TBL_LEN      ;Loop over all stored sectors
  235. CHKTIM: MOV     DX,LOW_TIM      ;Compare stored sector to so-far low time
  236.         CMP     [SI+4],DX       
  237.         JA      MORE_RECENT     ;If this one is more recent, don't use it
  238.         MOV     AX,DI           ;This one is older than previous oldest
  239.         MOV     BX,SI           ;Store sector bank address (DI) and table
  240.         MOV     DX,[SI+4]       ; entry (now in SI)
  241.         MOV     LOW_TIM,DX      ;And update the Low Time to this one
  242. MORE_RECENT:                    
  243.         ADD     DI,518          ;Move on to next stored sector
  244.         ADD     SI,518          ;And next table entry
  245.         LOOP    CHKTIM          ;Loop again until all covered
  246.         MOV     DI,AX           ;Get Sector bank address of oldest into DI
  247. FOUND:  mov     highwater,cx    ;remember how much we searched
  248.         POP     DX              ;Restore used registers
  249.         POP     SI              ;Old BX (data read-to-address) --> SI
  250.         POP     CX
  251.  
  252.         MOV     [BX],CX         ;Store the new CX as the sector's first word
  253.         MOV     [BX+2],DX       ;2nd word of Table is sector's DX
  254.         INC     TIME            ;Now find the new time
  255.         MOV     AX,TIME         ;Prepare to move it into 3rd word of Table
  256.         CMP     DH,0            ;Is this directory or FAT? (time-->FFFF)
  257.         JNE     SIDE1           ;If head is not 0, check other head
  258.         CMP     CX,9            ;Head zero, trk# 0, first sector? (directory)
  259.         JLE     DIR             ;Yes, this is a piece we always want stored
  260.         JMP     NOT_DIR         ;No, definitely not FAT or directory
  261.  
  262. SIDE1:  CMP     DH,1            ;Head 1?
  263.         JNE     NOT_DIR         ;No, this is not FAT or directory
  264.         CMP     CX,2            ;Part of the top of the directory?
  265.         JA      NOT_DIR         ;No, go to Not_Dir and set time
  266. DIR:    MOV     AX,0FFFFH       ;Dir or FAT, set time high so always kept
  267. NOT_DIR:MOV     [BX+4],AX       ;Not FAT or dir, store the incremented time
  268.  
  269.         PUSH    ES              ;And now get the data to fill the sector
  270.         POP     DS              ;SI, DI already set. Now set ES and DS for 
  271.         PUSH    CS              ; string move. 
  272.         POP     ES
  273.         MOV     CX,512          ;Move 512 bytes
  274. REP     MOVSB                   ;Right here
  275.         CLC                     ;Clear the carry flag (no error)
  276. FIN:    RET                     ;Error exit here (do not reset CY flag)
  277.  
  278. STORE_SECTOR    ENDP
  279.  
  280.         ;When Int13H called, CH=trk #         CL=sector #
  281.         ;                    DH=head # (0,1)  DL=Drive # (0,1,2,3)
  282.         ;                    AH=operation     AL=number of sectors
  283.         ;                    ES:BX=I/O buffer address
  284.       
  285.         ;  Operations are: 2=Read Sector(s)     3=Write Sectors
  286.         ;                  4=Verify Sectors     5=Format track     
  287.  
  288.         ;Format Buffer Contains 4 byte commands as reqd for 1 track
  289.         ;         Byte 1 = Track Number  Byte 2 = Head Number
  290.         ;         Byte 3 = Sector Number Byte 4 = Bytes/Sector Code
  291.  
  292.         ;Bytes/Sector code is: 00=128 01=256, 02=512 03=1024  
  293.  
  294.         ;Carry flag is 0 if operation successful, 1 for error
  295.  
  296.         ;AL = Number of bytes actually processed for Read/Write/Verify 
  297.  
  298.  
  299.         ;Table entry layout is:
  300.  
  301.           ;1st word of table entry: sector's CX (track number and sector number)
  302.           ;2nd word of Table entry: sector's DX (head number  and drive number)
  303.           ;3rd word is the incremented "time"
  304.           ;      unless sector is FAT or DIR, in which case it is FFFFh
  305.           ;Remaining 256 words are 512 bytes of the sector's contents. 
  306.  
  307.  
  308. zero      proc    near
  309.           pop     ax                   ;fix up the stack (offset)
  310. ;         pop     ax                   ;fix up the stack (CS)
  311.           pop     ax                   ;get back program length
  312.           mov     cx,ax                ;Also, zero all the bytes
  313.           shr     cx,1                 ;divide iterations by 2
  314.           push    cs                   
  315.           pop     es                   ;set up es
  316.           mov     si,offset table
  317.           mov     di,offset sector_data
  318.           repe    movsw                ;zero the world
  319.  
  320.           MOV     DX,OFFSET TABLE      ;To attach in memory, add # bytes to 
  321.           ADD     DX,AX                ; store to Table's location and use
  322.           INT     27H                  ; Int 27H exit and make resident
  323. zero      endp 
  324.  
  325. TABLE:    DW      3 DUP(0)        ;Table and sector storage begins right here
  326. Sector_data:  
  327.  
  328.                         ;First thing to write over is the following
  329.                         ; booster program.
  330.  
  331. cr            equ   13
  332. lf            equ   10
  333. parmptr       dw    81h           ;address of 'current' byte in parms
  334. radix         dw    10            ;radix for conversions
  335.  
  336. drivemsg      db    cr,lf,'Disk '
  337. drivewhere    db    ' ',' cache:' 
  338.               db    cr,lf,'$'
  339. driveerrmsg   db    cr,lf,'Disk err - use A-D',cr,lf,'$'
  340. sizeerrmsg    db    cr,lf,'Size err - use 24-124',cr,lf,'$' 
  341.  
  342. sizemsg       db    cr,lf
  343. sizedec       db    6 dup(' '),' bytes at '
  344. lochex        db    4 dup(' '),':0 '
  345. remdec        db    6 dup(' '),' free'
  346.               db    cr,lf,cr,lf,'$'
  347.  
  348. asciitable    db    '0123456789ABCDEF' ;table of characters 
  349.  
  350. asciibin      proc  near               ;si - source of characters (left end)
  351.                                        ;ax - contents in binary
  352.                                        ;cx - length in bytes
  353.               xor   ax,ax 
  354.               xor   bx,bx 
  355. asciiloop:
  356.               mov   bl,[si]          ;get character pointed to by SI
  357.               cmp   bl,' '           ;is character a blank?
  358.               je    asciiexit        ;if so, that is it.
  359.               cmp   bl,'0'
  360.               jl    asciierror
  361.               mul   radix            ;multiply ax by radix
  362.               cmp   bl,'9'
  363.               jg    asciihex         ;if character > 9 must be hex
  364.               and   bl,0fh           ;pick up numeric part
  365. asciiadd:                            ;add to accumulator
  366.               add   ax,bx
  367.               inc   si               ;scan right
  368.               loop  asciiloop
  369.               cmp   bl,bl            ;set zero flag
  370.               jmp   asciiret
  371.  
  372. asciihex:     cmp   radix,10         ;radix >10?
  373.               jle   asciierror       ;if not, error
  374.               or    bl,20h           ;make lower case 
  375.               cmp   bl,'a'
  376.               jl    asciierror
  377.               cmp   bl,'f'
  378.               jg    asciierror
  379.               sub   bl,87            ;turn 'A' into 10, etc
  380.               jmp   asciiadd
  381.  
  382. asciierror: 
  383.               xor   ax,ax                       ;return a zero on error
  384.  
  385. asciiexit:
  386.               cmp        bl," "                 ;set zero flag = no error
  387. asciiret:      
  388.               mov        parmptr,si             ;remember where we are at
  389.               mov        parml,cl               ;remember our length
  390.               ret
  391.  
  392. asciibin      endp
  393.  
  394. binascii      proc  near               ;di - target of characters (left just)
  395.                                        ;dx - most significant bits
  396.                                        ;ax - least significant bits
  397.                                        ;storage - radix
  398.               mov   si,offset asciitable  
  399.               xor   bh,bh              ;clear bh
  400.               xchg  bp,dx              ;ax,dx  contain data
  401. binloop:
  402.               xchg  ax,bp              ;get high word (dx)
  403.               xor   dx,dx              ;clear result
  404.               div   radix              ;divide ax by radix
  405.               xchg  bp,ax              ;get low word  (ax)
  406.               div   radix              ;divide 
  407.               mov   bl,dl              ;get into a register
  408.               mov   dl,cs:[bx+si]      ;get right ascii character
  409.               mov   [di],dl            ;and drop at target
  410.               dec   di                 ;set up for next character
  411.               cmp   ax,0               ;make sure something's left
  412.               jnz   binloop            ;if there is more loop
  413.               ret
  414.  
  415. binascii      endp 
  416.  
  417.  
  418. lineout       proc       near                   ;proc to type out a line
  419.               mov        byte ptr [di],cr       ;move in carriage return
  420.               inc        di
  421.               mov        byte ptr [di],lf       ;move in line feed
  422.               inc        di
  423.               mov        byte ptr [di],'$'      ;move in stopper
  424.               mov        ah,9h                  ;do screen i/o
  425.               int        21h
  426.               ret
  427.  
  428. lineout       endp 
  429.  
  430. scanparm      proc       near                   ;get start of next parm in SI
  431.               xor        cx,cx
  432.               mov        al,' '                 ;put blank in accumulator
  433.               mov        si,parmptr             ;get offset of parameter
  434.               mov        cl,parml               ;get length of remaining parm
  435.               cmp        cl,0                   ;is there any parm left?
  436.               je         scanret                ;if not, just exit
  437.  
  438. scanloop:     lodsb                             ;get byte pointed to by SI
  439.               cmp        al,' '                 ;is it blank?
  440.               jne        scangot
  441.               loop       scanloop               ;if so, loop on
  442.               jmp        scanset
  443. scangot:
  444.               dec        si                     ;back up over character
  445. scanset:
  446.               mov        parmptr,si             ;remember where we are at
  447.               mov        parml,cl               ;remember our length
  448. scanret:      
  449.               cmp        al,' '                 ;set zero flag
  450.               ret
  451. scanparm      endp
  452.  
  453.  
  454. Load_pgm  PROC    NEAR  ;This procedure intializes everything
  455.  
  456.           call       scanparm     ;call scan for start of parm
  457.           je         noparm       ;if none, skip checking parms
  458.           call       asciibin     ;turn chars into binary in ax
  459.  
  460.           mov        dx,offset sizeerrmsg
  461.           jnz        parmerr      ;if errors, skip out
  462.           mov        tbl_len,24   ;set minimum size
  463.           cmp        ax,24        ;smaller than minimum?
  464.           jl         parmerr      ;if so, complain
  465.           cmp        ax,124       ;larger than max?
  466.           jng        loadsize     ;if not, do what he asks
  467.           mov        tbl_len,124  ;if error then set max
  468.           jmp        parmerr      ;and complain
  469. loadsize:
  470.           mov        tbl_len,ax
  471.  
  472.           call       scanparm     ;call scan for start of parm
  473.           je         noparm       ;if none, skip checking parms
  474.  
  475.           and        al,255-20h   ;make upper case
  476.           mov        drivewhere,al;store in message
  477.           mov        dx,offset driveerrmsg
  478.           or         al,20h       ;make lower case
  479.           cmp        al,'a'       ;drive must be a to d
  480.           jl         parmerr
  481.           cmp        al,'d'
  482.           jg         parmerr      ;if not, will ignore
  483.           sub        al,'a'       ;make a = 0, b = 1, etc
  484.           mov        drive,al        
  485.  
  486.           mov         dx,offset drivemsg 
  487. parmerr:
  488.           mov        ah,9         ;dos function: type string 
  489.           int        21h 
  490.  
  491. noparm:
  492.           ASSUME  DS:INTERRUPTS   ;The data segment will be the Interrupt area
  493.           MOV     AX,INTERRUPTS
  494.           MOV     DS,AX
  495.  
  496.           MOV     AX,DISK_INT     ;Get the old interrupt service routine
  497.           MOV     INT13H,AX       ; address and put it into our location
  498.           MOV     AX,DISK_INT[2]  ; INT13H so we can call it.
  499.           MOV     INT13H[2],AX
  500.  
  501.           MOV     DISK_INT,OFFSET DISK_CACHE  ;Now load the address of Cache
  502.           MOV     DISK_INT[2],CS  ;routine into the Disk interrupt
  503.  
  504.           push    cs              ;back to normal addressibility
  505.           pop     ds                                            
  506.           assume  ds:code_seg     ;Make sure all labels found correctly
  507.  
  508.           MOV     AX,TBL_LEN      ;The number of sectors to store in cache
  509.           MOV     CX,518          ;Multiply by 518 (3 words of id and 512
  510.           MUL     CX              ; bytes of sector data) in AX
  511.  
  512.           push    ax              ;save ax 
  513.  
  514.           xor     dx,dx           ;clear hi bytes 
  515.           mov     di,offset sizedec+5  ;set target 
  516.           call    binascii
  517.  
  518.           push    cs              ;cs - where we are loaded
  519.           pop     ax              ;get it into ax for conversion
  520.  
  521.           mov     radix,16        ;housekeeping
  522.           xor     dx,dx           ;clear hi bytes 
  523.           mov     di,offset lochex+3  ;set target 
  524.           call    binascii
  525.  
  526.           push    cs              ;cs - where we are loaded
  527.           pop     bx              ;get it into bx for subtraction
  528.           mov     ax,pspsize      ;size of machine 5000h = 320k
  529.           sub     ax,bx           ;knock off where we are at
  530.           mov     dx,ax           ;get high bytes in accum ext
  531.           mov     cl,12
  532.           shr     dx,cl           ;orient correctly
  533.           mov     cl,4
  534.           shl     ax,cl           ;shift bytes in accum
  535.           pop     bx              ;get our length off stack
  536.           push    bx
  537.           sub     ax,bx           ;deduct length of this pgm
  538.           sbb     dx,0            ;if borrow, count it
  539.           mov     radix,10        ;now base 10
  540.           mov     di,offset remdec+5  ;set target 
  541.           call    binascii
  542.  
  543.           mov     dx,offset sizemsg 
  544.           mov     ah,9                 ;dos function: type string 
  545.           int     21h 
  546.  
  547.           call    zero                 ;finish up
  548.  
  549. Load_pgm  ENDP 
  550.  
  551. CODE_SEG  ENDS
  552.           END     FIRST           ;END 8088 will go to FIRST first.
  553.  
  554.